using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;

namespace Util.Helper
{
    public static class ExpressionHelper
    {
        /// <summary>
        /// 构造判断表达式（true）
        /// </summary>
        /// <typeparam name="T">类</typeparam>
        /// <returns></returns>
        public static Expression<Func<T, bool>> True<T>() { return f => true; }

        /// <summary>
        /// 构造判断表达式（false）
        /// </summary>
        /// <typeparam name="T">类</typeparam>
        /// <returns></returns>
        public static Expression<Func<T, bool>> False<T>() { return f => false; }

        /// <summary>
        /// 构造或表达式
        /// </summary>
        /// <typeparam name="T">类</typeparam>
        /// <param name="expr1">第一个表达式</param>
        /// <param name="expr2">第二个表达式</param>
        /// <returns></returns>
        public static Expression<Func<T, bool>> Or<T>(this Expression<Func<T, bool>> expr1,
                                                           Expression<Func<T, bool>> expr2)
        {
            var invokedExpr = Expression.Invoke(expr2, expr1.Parameters.Cast<Expression>());
            return Expression.Lambda<Func<T, bool>>
                  (Expression.OrElse(expr1.Body, invokedExpr), expr1.Parameters);
        }

        /// <summary>
        /// 构造且表达式
        /// </summary>
        /// <typeparam name="T">类</typeparam>
        /// <param name="expr1">第一个表达式</param>
        /// <param name="expr2">第二个表达式</param>
        /// <returns></returns>
        public static Expression<Func<T, bool>> And<T>(this Expression<Func<T, bool>> expr1,
                                                            Expression<Func<T, bool>> expr2)
        {
            var invokedExpr = Expression.Invoke(expr2, expr1.Parameters.Cast<Expression>());
            return Expression.Lambda<Func<T, bool>>
                  (Expression.AndAlso(expr1.Body, invokedExpr), expr1.Parameters); 
        }

        /// <summary>
        /// 构造属性表达式
        /// </summary>
        /// <typeparam name="T">类</typeparam>
        /// <param name="propertyName">T的属性名</param>
        /// <returns></returns>
        public static MemberExpression BuildMemberExpression<T>(string propertyName)
        {
            Type tType = typeof(T);
            ParameterExpression peAttr = Expression.Parameter(tType, "p");
            MemberExpression memberExpression = Expression.Property(peAttr, tType.GetProperty(propertyName));
            return memberExpression;
        }

        /// <summary>
        /// 构造等于Lambda表达式
        /// </summary>
        /// <typeparam name="T">类</typeparam>
        /// <typeparam name="V">值的类型</typeparam>
        /// <param name="propertyName">T的属性名</param>
        /// <param name="value">要比较的值</param>
        /// <returns></returns>
        public static Expression<Func<T, bool>> BuildEqualExpression<T, V>(string propertyName, V value)
        {
            Type tType = typeof(T);
            ParameterExpression peAttr = Expression.Parameter(tType, "p");
            MemberExpression memberExpression = Expression.Property(peAttr, tType.GetProperty(propertyName));

            ConstantExpression valueExpression = Expression.Constant(value);
            BinaryExpression binaryExpression = Expression.Equal(memberExpression, valueExpression);

            return Expression.Lambda<Func<T, bool>>(binaryExpression, peAttr);
        }

        /// <summary>
        /// 构造小于Lambda表达式
        /// </summary>
        /// <typeparam name="T">类</typeparam>
        /// <typeparam name="V">值的类型</typeparam>
        /// <param name="propertyName">T的属性名</param>
        /// <param name="value">要比较的值</param>
        /// <returns></returns>
        public static Expression<Func<T, bool>> BuildLessThanExpression<T, V>(string propertyName, V value)
        {
            Type tType = typeof(T);
            ParameterExpression peAttr = Expression.Parameter(tType, "p");
            MemberExpression memberExpression = Expression.Property(peAttr, tType.GetProperty(propertyName));

            ConstantExpression valueExpression = Expression.Constant(value);
            BinaryExpression binaryExpression = Expression.LessThan(memberExpression, valueExpression);
            return Expression.Lambda<Func<T, bool>>(binaryExpression, peAttr);
        }

        /// <summary>
        /// 构造小于等于Lambda表达式
        /// </summary>
        /// <typeparam name="T">类</typeparam>
        /// <typeparam name="V">值的类型</typeparam>
        /// <param name="propertyName">T的属性名</param>
        /// <param name="value">要比较的值</param>
        /// <returns></returns>
        public static Expression<Func<T, bool>> BuildLessThanOrEqualExpression<T, V>(string propertyName, V value)
        {
            Type tType = typeof(T);
            ParameterExpression peAttr = Expression.Parameter(tType, "p");
            MemberExpression memberExpression = Expression.Property(peAttr, tType.GetProperty(propertyName));

            ConstantExpression valueExpression = Expression.Constant(value);
            BinaryExpression binaryExpression = Expression.LessThanOrEqual(memberExpression, valueExpression);
            return Expression.Lambda<Func<T, bool>>(binaryExpression, peAttr);
        }

        /// <summary>
        /// 构造大于Lambda表达式
        /// </summary>
        /// <typeparam name="T">类</typeparam>
        /// <typeparam name="V">值的类型</typeparam>
        /// <param name="propertyName">T的属性名</param>
        /// <param name="value">要比较的值</param>
        /// <returns></returns>
        public static Expression<Func<T, bool>> BuildGreaterThanExpression<T, V>(string propertyName, V value)
        {
            Type tType = typeof(T);
            ParameterExpression peAttr = Expression.Parameter(tType, "p");
            MemberExpression memberExpression = Expression.Property(peAttr, tType.GetProperty(propertyName));

            ConstantExpression valueExpression = Expression.Constant(value);
            BinaryExpression binaryExpression = Expression.GreaterThan(memberExpression, valueExpression);
            return Expression.Lambda<Func<T, bool>>(binaryExpression, peAttr);
        }

        /// <summary>
        /// 构造大于等于Lambda表达式
        /// </summary>
        /// <typeparam name="T">类</typeparam>
        /// <typeparam name="V">值的类型</typeparam>
        /// <param name="propertyName">T的属性名</param>
        /// <param name="value">要比较的值</param>
        /// <returns></returns>
        public static Expression<Func<T, bool>> BuildGreaterThanOrEqualExpression<T, V>(string propertyName, V value)
        {
            Type tType = typeof(T);
            ParameterExpression peAttr = Expression.Parameter(tType, "p");
            MemberExpression memberExpression = Expression.Property(peAttr, tType.GetProperty(propertyName));

            ConstantExpression valueExpression = Expression.Constant(value);
            BinaryExpression binaryExpression = Expression.GreaterThanOrEqual(memberExpression, valueExpression);
            return Expression.Lambda<Func<T, bool>>(binaryExpression, peAttr);
        }
    }
}
